'use strict';
import * as Koa from 'koa';
import * as Router from 'koa-router';
import * as glob from 'glob';
import * as path from "path";
import { Exceptions, KLSYMBOL, RouterAttributes } from '../kalend';

import config from '../middleware/config';
import { readFileSync } from "fs";
var xmlparser = require('express-xml-bodyparser');//引入
xmlparser({ trim: false, explicitArray: false })


// 定义不变字段，在使用时读取
export const symbolRoutePrefix: symbol = Symbol("routePrefix");

/**
 * 路由执行类
 * 入口文件载入
 * const route = new Route(ctx: Koa);
 *
 * @class Route
 */
export class Route {
    // 静态 存储被修饰后的路由的地方
    static __DecoratedRouters: Array<{
        target: any,
        key: string,
        method: 'get' | 'post',
        path: string
    }> = [];


    private router: Router;
    private app: Koa;

    /**
     * Creates an instance of Route.
     *
     * @param {Koa} app
     *
     * @memberOf Route
     */
    constructor(app: Koa) {
        this.app = app;
        this.router = new Router();
    };

    /**
     * 注册路由
     * new Route(ctx:Koa).registerRouters(apipath);
     * @param controllerDir api文件路径
     */
    registerRouters(controllerDir: string) {
        // 载入api接口,使用sync同步载入
        glob.sync(path.join(controllerDir, './*.js')).forEach((item) => require(item));
        Route.__DecoratedRouters.forEach(itm => {
            const controller: Array<any> = [];
            let controllers: Array<Function> = (itm.target[KLSYMBOL.attributes][itm.key] as RouterAttributes).getCollection(); // Array.isArray(controller) ? controller : [controller];
            let prefixPath = itm.target[symbolRoutePrefix];
            if (prefixPath && (!prefixPath.startsWith('/'))) {
                prefixPath = '/' + prefixPath;
            }
            // 拼接api路由
            let routerPath = prefixPath + itm.path;

            let method = (itm.method || 'get').toLowerCase();//必须是小写的
            if (this.isRegister(this.router, method, routerPath)) {
                throw Exceptions.known(`路由器注册错误:${routerPath} 已定义`);
            }
            controllers.forEach((ctrl) => {
                (this.router as any)[method](routerPath, ctrl);
            });
        });

        this.proxy(this.router);
        this.app.use(this.router.routes());
        this.app.use(this.router.allowedMethods());
    };

    static allRouter: Array<any> = [];

    /**路由是否注册 */
    private isRegister(router: Router, method: String, path: string) {
        return router.stack.some(itm => {
            if (itm.methods.some(mitm => { return mitm === method.toUpperCase(); }) && itm.regexp.test(path)) {
                return true;
            }
            return false;
        });
    };

    private proxy(router: Router) {
        const lst: Map<{ method: string, routepath: string }, (ctx: Koa.Context, next: Function) => any> = new Map();
        const proxys = config.proxys;
        if (Array.isArray(proxys)) {
            config.proxys
                .forEach((itm) => {
                    lst.set(
                        { method: itm.method, routepath: itm.routepath },
                        (ctx: Koa.Context) => {
                            if (itm.file) {
                                const fp = path.join(__dirname, `./../../${itm.file.path}`);
                                ctx.body = readFileSync(fp);
                                ctx.attachment(ctx.params.file);
                            }
                        });
                });
        };

        for (const [cfg, middleware] of lst) {
            const method = (cfg.method as 'get' | 'post') || 'get';
            const rpath = cfg.routepath;
            const thispathexist = this.isRegister(this.router, method, rpath as string);
            if (thispathexist) {
                throw Exceptions.known(`路由器注册错误:${rpath} 已定义`);
            } else {
                this.router[method](rpath, middleware);
            }
        }
    };
}

